#include "DL_MH.h"
#include "Type_Define.h"
#include "PL.h"
#include "Data_Buffer.h"
#include "DL_MD.h"
#include "My_PARAM.h"
#include "PAGE_SPACE.h"
#include "DL_OD.h"
#include "DL_PD.h"
#include "usart.h"

//MH状态
MH_STATE_TYPE MH_STATE;
//MC结构
MC_Struct_TypeDef MC_STRUCT;



//读写方向
DirectionTypeDef MH_Dircetion;

//接收字节计数
//uint8_t Received_Count;

void INIT_DL_MH(void){
    MH_STATE=MH_Inactive_0;
    //初始化Buffer
    MC_STRUCT.MC=&BasicBufferInOut[0];
    
}

BOOL Check_CKT(void);
BOOL Check_M_Type(void);

/**************辅助函数***************/
void Compute_CKS(void);



/***************转移动作函数***************/

//除了开启定时器，还需要解析MC头
//void DL_MH_T1(void);
void DL_MH_T2(void);
//解析M序列
void DL_MH_T3(void);
void DL_MH_T4(void);
void DL_MH_T5(void);
void DL_MH_T6(void);

void DL_MH_T8(void);

void DL_MH_T9(void);
void DL_MH_T10(void);
//void DL_MH_T11(void);


//解析MC,以便判断需要接收多长的数据,更详细的填写MC_STRUCT（错）
//ParaMC在每次MC序列开始时候调用，仅用于判断是读写方向，其他MC_STRUCT信息
//在ModeHandler中判定

void ParasMC(void){
    
   //提取CKT中的MC Type信息
 
   uint8_t Direction=(*MC_STRUCT.MC)&0x80;
	 if(Direction!=0x80){ //如果读写方向是写,主写从
		 MC_STRUCT.RxBytes-=MC_STRUCT.OD_Len;  //站在主站的立场上,如果是写,主站接收的更少
		    MC_STRUCT.TxBytes+=MC_STRUCT.OD_Len; //
		   MC_STRUCT.SendBuffer+=MC_STRUCT.OD_Len; //发送缓冲指针更新
		 
	 }
   


}


void Event_MH_Conf_ACTIVE(void){
    if(MH_STATE==MH_Inactive_0){
		  	MH_STATE=MH_Idle_1;
			  PL_Recv_Ready();// 被唤醒，串口通信开始，串口中断开始
        
			  
       // DL_MH_T1();
        return;
    }

}

void Event_MH_Conf_INACTIVE(void){
    if(MH_STATE==MH_Idle_1){
        MH_STATE=MH_Inactive_0;
        //DL_MH_T11();
        return;
    }
}

//接收第一个一个字节，由PL层触发
void Event_PL_Transfer_Begin(void){
    //if(MH_STATE==MH_Idle_1){  只有在MH_IDLE状态，此函数才可能被调用
	      
        MH_STATE=MH_GetMessage_2;
        DL_MH_T2(); //在此函数中开启接受其他字节
       
   // }
 
}

void Event_MH_Completed(void){
    if(MH_STATE==MH_GetMessage_2){
        MH_STATE=MH_CheckMessage_3;
        DL_MH_T4();
    }
}



//在MaxUARTFramTimer的回调函数中调用
void Event_tm_MaxUARTframeTime(void){
    if(MH_STATE==MH_GetMessage_2){
		    MH_STATE=MH_Idle_1;
		  	DL_MH_T9();
			 //已经在接收中断接收MC,无需以下函数
		 
        
        
    }
}

void Event_tm_MaxCycleTime(void){
    if(MH_STATE==MH_Idle_1){
        DL_MH_T10();
    }
}

void Event_ChecksumError(void){
    if(MH_STATE==MH_CheckMessage_3){
			   MH_STATE=MH_Idle_1;
			  
			   
        
    }
}

void Event_TypeError_and_not_ChecksumError(void){
    if(MH_STATE==MH_CheckMessage_3){
		  	MH_STATE=MH_Idle_1;
			   //已经在接收中断接收MC,无需以下函数
		 
        
    }
}

void Event_No_error(void){
    if(MH_STATE==MH_CheckMessage_3){
        MH_STATE=MH_CreateMessage_4;
        DL_MH_T5();
    }
}

void Event_MH_Ready(void){
    if(MH_STATE==MH_CreateMessage_4){
		    MH_STATE=MH_Idle_1;    
			  
        DL_MH_T6();
			   //已经在接收中断接收MC,无需以下函数
			  PL_Recv_Ready();// 通知串口接收中断,等待接收首字MC   
    }
}


/***************转移动作函数***************/

//DL_MH_T2与硬件绑定太多 , 应该放在PL中

//无需T3，T3已经在PL文件的Receive_Next_Words函数中调用了
//void DL_MH_T3(void){
//    //重启定时器UartframeTimer
//    PL_Start_MaxUARTframeTimer();
//    //判断是否接收完毕
//    Received_Count++;
//    
//    if(Received_Count>=MC_STRUCT.RxBytes){ //接收完毕
//       Event_MH_Completed();// 通知接收完毕
//    }
//}



//如果处于MD_OPERATE 状态，则开启 MaxUARTFrameTimer 和 MaxCycleTimer 两个定时器
void DL_MH_T2(void){
	if(MD_STATE==MD_OPerate_4){
		  PL_Start_MaxUARTframeTimer();
		  PL_Start_MaxCycleTimer();
		
	}
	
}

void DL_MH_T4(void){
 
    PL_Stop_MaxUARTframTimer();  //停止MaxUARTFrame定时器
    BOOL checksumError=Check_CKT();
    BOOL TypeError=Check_M_Type();
    
    if(checksumError){
        Event_ChecksumError();
        return;
    }else if(TypeError){
        Event_TypeError_and_not_ChecksumError();
        return;
    }else{
        Event_No_error();
        return;
    }
    
}

void DL_MH_T5(void){
    
    Event_PD_ind();
    Event_OD_ind();
}

void DL_MH_T6(void){
    Compute_CKS();
    PL_Transfer_Rep();
	  PL_Stop_MaxCycleTimer(); //此处有修改协议，此时正常完成一个MH周期，正常停止MaxCycleTimer
}

void DL_MH_T8(void){
    Event_MHInfo_ILLEGAL_MESSAGETYPE();
}

void DL_MH_T9(void){
    //关闭定时器
	   PL_Stop_MaxUARTframTimer();
	   PL_Stop_MaxCycleTimer();
}

void DL_MH_T10(void){
    //当为执行器时候，错误情况下的安全防护动作
   Actions_of_Actuator_In_Error();
}


BOOL Check_CKT(void){
    uint8_t CKT=(*MC_STRUCT.CKT)&0x3F;
    *MC_STRUCT.CKT=0x00;
    uint8_t SeedValue=0x52;
    for(uint8_t i=0;i<MC_STRUCT.RxBytes;i++){
        SeedValue=BasicBufferInOut[i]^SeedValue;        
    }
    //压缩checksum
    uint8_t bit8=SeedValue&0x80;
    uint8_t bit7=SeedValue&0x40;
    uint8_t bit6=SeedValue&0x20;
    uint8_t bit5=SeedValue&0x10;
    uint8_t bit4=SeedValue&0x08;
    uint8_t bit3=SeedValue&0x04;
    uint8_t bit2=SeedValue&0x02;
    uint8_t bit1=SeedValue&0x01;
    uint8_t Checksum6=0x00;
    Checksum6=Checksum6|((bit8>>2)^bit6^(bit4<<2)^(bit2<<4));
    Checksum6=Checksum6|((bit7>>2)^bit5^(bit3<<2)^(bit1<<4));
    Checksum6=Checksum6|((bit8>>1)^bit7)>>3;
    Checksum6=Checksum6|((bit6>>1)^bit5)>>2;
    Checksum6=Checksum6|((bit4>>1)^bit3)>>1;
    Checksum6=Checksum6|(bit2>>1)^bit1;

    if(Checksum6==CKT){
        return True;
    }else
    {
        return False;
    }
   
}

void Compute_CKS(void){
    uint8_t CKS_Saved=(*MC_STRUCT.CKS)&0xC0;
 
    *MC_STRUCT.CKS=0x00;
    uint8_t SeedValue=0x52;
    for(uint8_t i=0;i<MC_STRUCT.TxBytes;i++){
       // SeedValue=BasicBufferInOut[i]^SeedValue; 
       SeedValue=(*(MC_STRUCT.CKS-MC_STRUCT.TxBytes+i+1))^SeedValue;

    }
    //压缩checksum
    uint8_t bit8=SeedValue&0x80;
    uint8_t bit7=SeedValue&0x40;
    uint8_t bit6=SeedValue&0x20;
    uint8_t bit5=SeedValue&0x10;
    uint8_t bit4=SeedValue&0x08;
    uint8_t bit3=SeedValue&0x04;
    uint8_t bit2=SeedValue&0x02;
    uint8_t bit1=SeedValue&0x01;
    uint8_t Checksum6=0x00;
    Checksum6=Checksum6|((bit8>>2)^bit6^(bit4<<2)^(bit2<<4));
    Checksum6=Checksum6|((bit7>>2)^bit5^(bit3<<2)^(bit1<<4));
    Checksum6=Checksum6|((bit8>>1)^bit7)>>3;
    Checksum6=Checksum6|((bit6>>1)^bit5)>>2;
    Checksum6=Checksum6|((bit4>>1)^bit3)>>1;
    Checksum6=Checksum6|(bit2>>1)^bit1;

    *MC_STRUCT.CKS=CKS_Saved|Checksum6;
   
}

 
BOOL Check_M_Type(void){
	  uint8_t MCType_of_CKT=((*MC_STRUCT.CKT)&0xC0)>>6;
	  uint8_t MCType_of_Page_In_Pre=(M_squenceCapability&0x30)>>4;
	  uint8_t MCType_of_Page_In_Oper=(M_squenceCapability&0x0E)>>1;
 
    if(MD_STATE==MD_Startup_2||MD_STATE==MD_Idle_0){
        if(MCType_of_CKT==0){
            return True;
        }else
        {
            return False;
        }
        
    }

    if(MD_STATE==MD_PreOperate_3&&MCType_of_CKT==MCType_of_Page_In_Pre){
        return True;
    }else if(MD_STATE==MD_OPerate_4&&MCType_of_CKT==MCType_of_Page_In_Oper){
        return True;
    }else{
        return False;
    }

}
